package com.chenziwen.scala.chapter05

object Scala01_Object {

  def main(args: Array[String]): Unit = {
    // 当使用new构建对象时，等同于调用类的主构造器，这种构造方式类似于JavaScript中对象的构建
    // 执行主构造器时，类体、构造器体、函数体中所有的语句都会执行

    val user = new User()
    println(user)

    // 主构造器无参时，调用时的小括号也可以省略
    val person = new Person
    println(person)

    // 构造器也是函数，传递参数和使用方法和前面的函数部分内容没有区别（参数个数、参数默认值、带参调用等）
    val cat = new Cat("xixi")
    println(cat)

    val dog1 = new Dog("大黄")
    println(dog1.name)

    val dog2 = new Dog("小黑", 3)
    println(dog2.name + "->" + dog2.age)

    val wolf = new Wolf("小红")
    println(wolf)

    // Scala中，如果伴生类构造器被私有化，仍然需要该对象，可以使用伴生对象，并且该伴生对象是单例的
    // com.chenziwen.scala.chapter05.Sheep$@1134affc 所以，其实当前伴生类对象是该Sheep$对象的一个实例
    val sheep1 = Sheep
    val sheep2 = Sheep
    // sheep1和sheep2的内存地址是一样的，也就是说这个对象是单例的
    println(sheep1)
    println(sheep2)
  }

}

// 主构造器的声明直接放置于类名之后
class User() {
  // 花括号内内容，可以成为：类体、构造器体、函数体
  println("主构造器中的第一行代码")
  println("主构造器中的第二行代码")
  println("主构造器中的第三行代码")
}

class Person {
  println("主构造器无参，小括号可以省略")
}

class Cat(name: String, age: Int = 8) {
  println(name + "->" + age)
}

class Dog() {
  var name = ""
  var age = 0

  // Scala中辅助构造器的名称为this（这个和Java中是不一样的），多个辅助构造器通过不同的参数列表进行区分
  // 这里this指代的是构造器，也就是类名
  def this(name: String) {
    // 辅助构造器无论是直接或间接，最终都一定要调用主构造器，执行主构造器的逻辑（因为辅助构造器不能直接构造对象）
    // 调用主构造器的逻辑，必须放在第一行，主构造器无参，小括号可以省略
    this
    this.name = name
  }

  def this(name: String, age: Int) {
    // 调用之前已经声明过的构造器，这里所调用的构造器一定要在当前构造器之前声明，不然编译无法通过，因为函数式编程强调的是过程，编译到此处时，如果调用的辅助构造器没有定义好，编译就无法通过
    this(name)
    this.age = age
  }
}

// 如果想让主构造器私有化，可以在()前加上private关键字，这样用户只能通过辅助构造器来构造对象了
class Wolf private() {
  // 辅助构造器不能和主构造器定义成一样的，这样虽然编译可以通过，但是执行会出错，因为两个构造方法重复定义了
  def this(name: String) {
    this
    println(name)
  }
}


// 单例对象，在Scala中，如果一个类的主构造器被声明为了私有的，那么它的伴生对象就是它的单例对象
class Sheep private() {

}

// 伴生对象既然是一个单例对象，也就意味着类已经声明过了，所以，伴生类对象是不能声明构造器的
// 从技术的角度来讲，伴生对象和伴生类其实是两个不同的类，伴生对象所对应的类可以简单的理解为半生类的辅助工具类
// 而伴生对象就是这个辅助工具类的单例对象，专门用于处理伴生类中静态资源的相关功能
object Sheep {

}
